package ru.hh.team02.chat.messaging;

import java.util.ArrayList;
import java.util.Set;

import ru.hh.team02.chat.client.*;
import ru.hh.team02.chat.server.ChatServer;
import ru.hh.team02.chat.utils.BatchBlockingQueue;
import ru.hh.team02.chat.utils.SimpleBlockingQueue;

public class SendingQueue {
    private BatchBlockingQueue<Message> blockingQueue = new SimpleBlockingQueue<Message>();

    /**
     * Create a new SendingBlockingQueue object
     * 
     * @param numberOfThreads
     *            Number of sending threads.
     */
    public SendingQueue(int numberOfThreads) {
        // Creating sending threads and starting them
        for (int i = 0; i < numberOfThreads; i++) {
            Thread sender = new Thread(new Sender());
            sender.start();
        }
    }

    class Sender implements Runnable {
        public void run() {
            while (true) {
                try {
                    // Get hold of a message from a queue
                    Message message = getMessage();

                    // Send the message in this thread
                    message.sendMessage();
                } catch (InterruptedException e) {
                    // This shouldn't happen as there is nobody to terminate threads
                    // according to the contract.
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * Get a message from the queue.
     * 
     * @return message
     * @throws InterruptedException
     *             if queue is empty and in terminating mode.
     */
    private Message getMessage() throws InterruptedException {
        return blockingQueue.get();
    }

    /**
     * Add message to the queue
     * 
     * @param message
     *            message to add to the queue for sending
     * @exception IllegalStateException
     *                Thrown when the queue is closed
     */
    public void add(Message message) {
        blockingQueue.add(message);
    }

    /**
     * Create a bunch of messages to all the clients of the room and put the
     * messages in the queue for sending to them. This method is just for
     * optimization, as we may block the queue only once and add all the
     * messages instead of blocking and unblocking the queue for each message.
     * 
     * @param message
     *            message to add to the queue for sending
     * @param room
     *            Room of clients the message is addressed to
     * @exception IllegalStateException
     *                Thrown when the queue is closed
     */
    public void add(String text, String room) {
        Set<Client> recepients = ChatServer.registry.getClientsFromRoom(room);

        // Prepare the array of messages before blocking the queue
        // to block the queue for only time needed to add these messages without
        // waiting for their generation.
        ArrayList<Message> messages = new ArrayList<Message>(recepients.size());
        for (Client recepient : recepients) {
            messages.add(new Message(text, recepient));
        }

        blockingQueue.addAll(messages);
    }
}
